﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Complaint.Models.Dtos.Enums;
using Complaint.Models.Services;
using Complaint.Repositories;

namespace Complaint.Models
{
    public class ComplaintModel : BaseModel<ComplaintRepository>, IModel<Dtos.Complaint>
    {
        #region IModel<Complaint> Members

        public IList<Dtos.Complaint> Retrieve()
        {

            return Repository.FindAll().ToList();
        }

        public void Create(Dtos.Complaint dto)
        {

            if (dto != null) Repository.Create(dto);
        }

        public void Update(Dtos.Complaint dto)
        {

            if (dto != null) Repository.Update(dto);
        }

        public void Delete(Dtos.Complaint dto)
        {

            if (dto != null) Repository.Delete(dto);
        }

        public IList<Dtos.Complaint> FindByName(string name)
        {

            return Repository.FindByName(name).ToList();
        }

        public Dtos.Complaint FindById(int id)
        {

            return Repository.FindById(id);
        }

        #endregion

        public void Create(Dtos.Complaint dto, string from)
        {
            CheckDto(dto);

            Repository.Create(dto);

            if (dto.PassOn)
            {
                SendPassOnEmail(dto, from);
            }
        }

        private static void SendPassOnEmail(Dtos.Complaint dto, string from)
        {
            var subject = string.Format("iComplain User complaint #{0}: {1}", dto.ComplaintID, dto.Title);
            var message = ComposeComplaintEmail(dto);

            var sendMailThread = new Thread(() => new MailService().Send(
                                                      from,
                                                      dto.Organisation.CustomerCareEmail,
                                                      subject,
                                                      message,
                                                      dto.Proof,
                                                      false
                                                      )) { IsBackground = true };

            sendMailThread.Start();
        }

        private static void CheckDto(Dtos.Complaint dto)
        {
            if (dto == null)
                throw new ArgumentNullException();

            if (dto.User == null || dto.Organisation == null)
                throw new ArgumentException();
        }

        private static string ComposeComplaintEmail(Dtos.Complaint dto)
        {
            var sb = new StringBuilder();
            sb.AppendLine("There is a complaint lodged on iComplain.info against your organisation, please investigate.");
            sb.AppendLine("Please do not reply to this email, contact the complainer using details blow instead.\n");
            sb.AppendFormat("Author: {0}", dto.User.FullName);
            sb.AppendLine();
            sb.AppendFormat("Email: {0}", dto.User.Email);
            sb.AppendLine();
            sb.AppendFormat("Date added: {0}\n", dto.DateLodged);
            sb.AppendLine();
            sb.Append(dto.Body);

            return sb.ToString();
        }

        public IList<Dtos.Complaint> Retrieve(int top)
        {

            return Repository.FindAll(top).ToList();
        }

        public IList<Dtos.Complaint> Retrieve(LoadComplaint loadOption)
        {

            return Repository.FindAll(loadOption).ToList();
        }

        public IList<Dtos.Complaint> Retrieve(int pageNumber, int pageSize, out int totalNumber)
        {

            return Repository.FindAll(pageNumber, pageSize, out totalNumber).ToList();
        }

        public IList<Dtos.Complaint> Retrieve(int pageNumber, int pageSize, out int totalNumber, DateTime? dateFrom, DateTime? dateTo)
        {

            return Repository.FindAll(pageNumber, pageSize, out totalNumber, dateFrom, dateTo).ToList();
        }

        public IList<Dtos.Complaint> Retrieve(LoadComplaint loadOption, int pageNumber, int pageSize, out int totalNumber)
        {

            return Repository.FindAll(loadOption, pageNumber, pageSize, out totalNumber).ToList();
        }

        public IList<Dtos.Complaint> Retrieve(LoadComplaint loadOption, int pageNumber, int pageSize, out int totalNumber, int categoryId)
        {

            return Repository.FindAll(loadOption, pageNumber, pageSize, out totalNumber, categoryId).ToList();
        }

        public IList<Dtos.Complaint> Retrieve(LoadComplaint loadOption, int pageNumber, int pageSize, out int totalNumber, DateTime? dateFrom, DateTime? dateTo)
        {

            return Repository.FindAll(loadOption, pageNumber, pageSize, out totalNumber, dateFrom, dateTo).ToList();
        }

        public IList<Dtos.Complaint> Retrieve(LoadComplaint loadOption, int pageNumber, int pageSize, out int totalNumber, DateTime? dateFrom, DateTime? dateTo, int[] categoryId)
        {

            return Repository.FindAll(loadOption, pageNumber, pageSize, out totalNumber, dateFrom, dateTo, categoryId).ToList();
        }

        public Dtos.Complaint FindById(int id, LoadComplaint loadOption)
        {

            return Repository.FindById(id, loadOption);
        }

        public IList<Dtos.Complaint> FindByName(string name, LoadComplaint loadOption)
        {

            return Repository.FindByName(name, loadOption).ToList();
        }

        public IList<Dtos.Complaint> FindByName(string name, LoadComplaint loadOption, DateTime? dateFrom, DateTime? dateTo)
        {

            return Repository.FindByName(name, loadOption, dateFrom, dateTo).ToList();
        }

        public IList<Dtos.Complaint> FindByOrganisation(int id, LoadComplaint loadOption)
        {

            return Repository.FindByOrganisation(id, loadOption).ToList();
        }

        public IList<Dtos.Complaint> FindByOrganisation(int id, LoadComplaint loadOption, int pageNumber, int pageSize, out int totalNumber)
        {

            return Repository.FindByOrganisation(id, loadOption, pageNumber, pageSize, out totalNumber).ToList();
        }

        public IList<Dtos.Complaint> FindByOrganisation(string name, LoadComplaint loadOption, int pageNumber, int pageSize, out int totalNumber)
        {

            return Repository.FindByOrganisation(name, loadOption, pageNumber, pageSize, out totalNumber).ToList();
        }

        public IList<Dtos.Complaint> FindByOrganisation(string name, LoadComplaint loadOption)
        {

            return Repository.FindByOrganisation(name, loadOption).ToList();
        }

        public IList<Dtos.Complaint> FindByOrganisation(string name, LoadComplaint loadOption, DateTime? dateFrom, DateTime? dateTo)
        {

            return Repository.FindByOrganisation(name, loadOption, dateFrom, dateTo).ToList();
        }

        public IList<Dtos.Complaint> FindByUser(int id, LoadComplaint loadOption, int pageNumber, int pageSize, out int totalNumber)
        {

            return Repository.FindByUser(id, loadOption, pageNumber, pageSize, out totalNumber).ToList();
        }

        public IList<Dtos.Complaint> FindByUser(int id, LoadComplaint loadOption)
        {

            return Repository.FindByUser(id, loadOption).ToList();
        }

        public IList<Dtos.Complaint> FindByUser(string name, LoadComplaint loadOption)
        {

            return Repository.FindByUser(name, loadOption).ToList();
        }

        public IList<Dtos.Complaint> FindByUser(string name, LoadComplaint loadOption, DateTime? dateFrom, DateTime? dateTo)
        {

            return Repository.FindByUser(name, loadOption, dateFrom, dateTo).ToList();
        }

        public IList<Dtos.Complaint> FindByUser(string name, LoadComplaint loadOption, int pageNumber, int pageSize, out int totalNumber)
        {

            return Repository.FindByUser(name, loadOption, pageNumber, pageSize, out totalNumber).ToList();
        }

        public IList<Dtos.Complaint> FindByKeywords(string keywords, LoadComplaint loadOption)
        {

            return Repository.FindByKeywords(keywords, loadOption).ToList();
        }

        public IList<Dtos.Complaint> FindByKeywords(string keywords, LoadComplaint loadOption, int pageNumber, int pageSize, out int totalNumber)
        {

            return Repository.FindByKeywords(keywords, loadOption, pageNumber, pageSize, out totalNumber).ToList();
        }

        public IList<Dtos.Complaint> FindByKeywords(string keywords, LoadComplaint loadOption, int pageNumber, int pageSize, out int totalNumber, DateTime? dateFrom, DateTime? dateTo)
        {

            return Repository.FindByKeywords(keywords, loadOption, pageNumber, pageSize, out totalNumber, dateFrom, dateTo).ToList();
        }

        public IList<Dtos.Complaint> FindByKeywords(string keywords, LoadComplaint loadOption, int pageNumber, int pageSize, out int totalNumber, DateTime? dateFrom, DateTime? dateTo, int[] categoryId)
        {

            return categoryId.Length == 0
                ? Repository.FindByKeywords(keywords, loadOption, pageNumber, pageSize, out totalNumber, dateFrom, dateTo).ToList()
                : Repository.FindByKeywords(keywords, loadOption, pageNumber, pageSize, out totalNumber, dateFrom, dateTo, categoryId).ToList();
        }
    }
}